/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** *****************************************************************************************************
 * \file     Lin.c                                                                                      *
 * \brief    AUTOSAR 4.3.1 MCAL Lin Driver                                                              *
 *                                                                                                      *
 * <table>                                                                                              *
 * <tr><th>Date           <th>Version                                                                   *
 * <tr><td>2024/11/25     <td>1.0.0                                                                     *
 * </table>                                                                                             *
 *******************************************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

/********************************************************************************************************
 *                                      Include header files                                            *
 *******************************************************************************************************/
#include "Lin.h"
#include "Mcal.h"
#if (STD_ON == LIN_DEV_ERROR_DETECT)
#include "Det.h"
#endif /* STD_ON == LIN_DEV_ERROR_DETECT */

// #if ( LIN_USE_ECUM_BSW_ERROR_HOOK == STD_ON )
// #include "EcuM_Error.h"
// #endif

/********************************************************************************************************
 *                                  Global Variable Declarations                                        *
 *******************************************************************************************************/
#if (STD_ON == LIN_CORE0_ENABLE)
#define LIN_CORE0_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Lin_MemMap.h"
static Lin_HandlerType Lin_HandlerCore0 LOCATE_ALIGNED(LIN_CACHE_LINE);
#define LIN_CORE0_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Lin_MemMap.h"
#endif /* #if (STD_ON == LIN_CORE0_ENABLE) */

#if (STD_ON == LIN_CORE1_ENABLE)
#define LIN_CORE1_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Lin_MemMap.h"
static Lin_HandlerType Lin_HandlerCore1 LOCATE_ALIGNED(LIN_CACHE_LINE);
#define LIN_CORE1_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Lin_MemMap.h"
#endif /* #if (STD_ON == LIN_CORE1_ENABLE) */

#if (STD_ON == LIN_CORE2_ENABLE)
#define LIN_CORE2_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Lin_MemMap.h"
static Lin_HandlerType Lin_HandlerCore2 LOCATE_ALIGNED(LIN_CACHE_LINE);
#define LIN_CORE2_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Lin_MemMap.h"
#endif /* #if (STD_ON == LIN_CORE2_ENABLE) */

#if (STD_ON == LIN_CORE3_ENABLE)
#define LIN_CORE3_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Lin_MemMap.h"
static Lin_HandlerType Lin_HandlerCore3 LOCATE_ALIGNED(LIN_CACHE_LINE);
#define LIN_CORE3_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Lin_MemMap.h"
#endif /* #if (STD_ON == LIN_CORE3_ENABLE) */

#define LIN_START_SEC_CONST_UNSPECIFIED
#include "Lin_MemMap.h"
Lin_HandlerType * const Lin_Handler[CPU_MAX_CORE_NUMBER] =
{
#if (STD_ON == LIN_CORE0_ENABLE)
    &Lin_HandlerCore0,
#else /* #if (STD_ON == LIN_CORE0_ENABLE) */
    NULL_PTR,
#endif /* #if (STD_ON == LIN_CORE0_ENABLE) */

#if (STD_ON == LIN_CORE1_ENABLE)
    &Lin_HandlerCore1,
#else /* #if (STD_ON == LIN_CORE1_ENABLE) */
    NULL_PTR,
#endif /* #if (STD_ON == LIN_CORE1_ENABLE) */

#if (STD_ON == LIN_CORE2_ENABLE)
    &Lin_HandlerCore2,
#else /* #if (STD_ON == LIN_CORE2_ENABLE) */
    NULL_PTR,
#endif /* #if (STD_ON == LIN_CORE2_ENABLE) */

#if (STD_ON == LIN_CORE3_ENABLE)
    &Lin_HandlerCore3,
#else /* #if (STD_ON == LIN_CORE3_ENABLE) */
    NULL_PTR,
#endif /* #if (STD_ON == LIN_CORE3_ENABLE) */
};
#define LIN_STOP_SEC_CONST_UNSPECIFIED
#include "Lin_MemMap.h"

/********************************************************************************************************
 *                                  Global Constant Declarations                                        *
 *******************************************************************************************************/
#define LIN_START_SEC_VAR_INIT_UNSPECIFIED
#include "Lin_MemMap.h"

/* PRQA S 1751 10 */
/* for lin_go_to_sleep : sleep frame */
uint8 SleepFrame[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
Lin_PduType linSleepPduInfo =
{
    .Pid = LIN_SLEEP_PID,
    .Cs = LIN_CLASSIC_CS,
    .Drc = LIN_MASTER_RESPONSE,
    .Dl = 8,
    .SduPtr = SleepFrame,
};
#define LIN_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Lin_MemMap.h"

#define LIN_START_SEC_CODE
#include "Lin_MemMap.h"
/********************************************************************************************************
 *                                  Private Function Declarations                                       *
 *******************************************************************************************************/
static Std_ReturnType Lin_ChannelDetCheck(uint8 Channel, uint8 serviceId)
{
    Std_ReturnType errorId = E_OK;
    uint8 coreId = Lin_GetCoreId();

    if (LIN_NUM_CHANNELS <= Channel)
    {
        errorId = LIN_E_INVALID_CHANNEL;
    }
    else if (NULL_PTR == Lin_Handler[coreId])
    {
        errorId = LIN_E_ILLEGAL_RES_ACCESS;
    }
    else if (LIN_UNINIT == Lin_Handler[coreId]->driverStatus)
    {
#if(STD_ON == LIN_DEV_ERROR_DETECT)
        (void)Det_ReportError(LIN_MODULE_ID, 0, serviceId, LIN_E_UNINIT);
#else /** #if(STD_ON == LIN_DEV_ERROR_DETECT) */
        LIN_DUMMY_STATE(serviceId);
#endif /** #if(STD_ON == LIN_DEV_ERROR_DETECT) */
        errorId = E_NOT_OK;
    }
    else if (coreId != Lin_Handler[coreId]->config->channels[Channel].coreId)
    {
        errorId = LIN_E_ILLEGAL_RES_ACCESS;
    }

    return errorId;
}

/********************************************************************************************************
 *                                  Global Function Declarations                                        *
 *******************************************************************************************************/
/******************************************************************************************************
 * Lin_Init           : LIN driver initialization.
   Return type        : None
   Parameter          : Lin_ConfigType
******************************************************************************************************/
void Lin_Init(const Lin_ConfigType *Config)
{
    uint8 nodeCtr;
    Std_ReturnType retStatus;
    uint8 coreId = Lin_GetCoreId();

    if (Config != NULL_PTR)
    {
        /* Check Lin driver is not initialized*/
        if ((NULL_PTR != Lin_Handler[coreId]) && (Lin_Handler[coreId]->driverStatus == LIN_UNINIT))
        {
            Lin_Handler[coreId]->config = Config;
            Lin_Handler[coreId]->driverStatus = LIN_INIT;
            for (nodeCtr = 0; nodeCtr < Config->numberOfNodes; nodeCtr++)
            {
                if (Lin_Handler[coreId]->config->channels[nodeCtr].coreId == coreId)
                {
                    Lin_Handler[coreId]->channelStatus[nodeCtr] = LIN_CH_SLEEP_PENDING;
                    Lin_Handler[coreId]->channelInfo[nodeCtr].ChannelState = LIN_NOT_OK;
                    retStatus = Lin_NodeInit(nodeCtr);
                    if (E_OK == retStatus)
                    {
                        Lin_Handler[coreId]->channelInfo[nodeCtr].ChannelState = LIN_CH_SLEEP;
                        Lin_Handler[coreId]->wakeupFlag[nodeCtr] = FALSE;
                        Lin_Handler[coreId]->wakeupSelfFlag[nodeCtr] = FALSE;
                    }
                    else
                    {
                        Lin_Handler[coreId]->driverStatus = LIN_UNINIT;
                        break;
                    }
                }
            }
        }
#if(STD_ON == LIN_DEV_ERROR_DETECT)
        else
        {
            (void)Det_ReportError(LIN_MODULE_ID, 0, LIN_INIT_ID, LIN_E_STATE_TRANSITION);
        }
#endif /** #if(STD_ON == LIN_DEV_ERROR_DETECT) */
    }
#if(STD_ON == LIN_DEV_ERROR_DETECT)
    else
    {
        (void)Det_ReportError(LIN_MODULE_ID, 0, LIN_INIT_ID, LIN_E_INVALID_POINTER);
    }
#endif /** #if(STD_ON == LIN_DEV_ERROR_DETECT) */
}

/******************************************************************************************************
 * Lin_GoToSleep      : LIN function requesting driver to transmit a sleep command on the LIN
                        channel.
   Return type        : Std_ReturnType E_OK when sleep command accepted
                                       E_NOT_OK when sleep command not accepted
   Parameter          : Channel which needs to go sleep
******************************************************************************************************/
Std_ReturnType Lin_GoToSleep(uint8 Channel)
{
    const Lin_Uart *locNodeCfg;
    Lin_ChannelInfoType *Lin_ChannelPtr;
    Std_ReturnType retVal = E_NOT_OK;
    Std_ReturnType errorId;
    Lin_ChannelPtr = NULL_PTR;
    uint8 coreId = Lin_GetCoreId();

    /* Check Lin driver common parameter */
    errorId = Lin_ChannelDetCheck(Channel, LIN_GOTOSLEEP_ID);

    if (E_OK == errorId)
    {
        locNodeCfg = &Lin_Handler[coreId]->config->channels[Channel];
        if (locNodeCfg->dataPtr.mode == LIN_UART_MASTER)
        {
            Lin_ChannelPtr = &Lin_Handler[coreId]->channelInfo[Channel];
            /* only master mode support goto sleep cmd */
            if (((Lin_ChannelPtr->ChannelState) != LIN_CH_SLEEP))
            {
                Std_ReturnType sleepRet = E_NOT_OK;
                Lin_Handler[coreId]->sleepFlag[Channel] = TRUE;
                sleepRet = Lin_SendFrame(Channel, &linSleepPduInfo);
                if (sleepRet == E_OK)
                {
                    Lin_ChannelPtr->nodeData.currentState = LIN_WAIT_FOR_WAKEUP;
                    Lin_Handler[coreId]->channelStatus[Channel] = LIN_CH_SLEEP_PENDING;
                    Lin_ChannelPtr->ChannelState = LIN_CH_SLEEP;
                    Lin_Handler[coreId]->wakeupFlag[Channel] = FALSE;
                    retVal = E_OK;
                }
            }
            else
            {
                errorId = LIN_E_STATE_TRANSITION;
            }
        }
        else
        {
            errorId = LIN_E_INVALID_CHANNEL;
        }
    }

#if(STD_ON == LIN_DEV_ERROR_DETECT)
    if ((E_OK != errorId) && (E_NOT_OK != errorId))
    {
        (void)Det_ReportError(LIN_MODULE_ID, 0, LIN_GOTOSLEEP_ID, errorId);
    }
#endif /** #if(STD_ON == LIN_DEV_ERROR_DETECT) */

    return retVal;
}

/******************************************************************************************************
 * Lin_GoToSleepInternal      : LIN function sets the channel to LIN_CH_SLEEP, enables wakeup detection.
   Return type                : Std_ReturnType E_OK when sleep command accepted
                                               E_NOT_OK when sleep command not accepted
   Parameter                  : Channel which needs to go sleep
******************************************************************************************************/
Std_ReturnType Lin_GoToSleepInternal(uint8 Channel)
{
    const Lin_Uart *locNodeCfg;
    Lin_ChannelInfoType *Lin_ChannelPtr;
    Std_ReturnType retVal = E_NOT_OK;
    Std_ReturnType errorId;
    Lin_ChannelPtr = NULL_PTR;
    uint8 coreId = Lin_GetCoreId();

    /* Check Lin driver common parameter */
    errorId = Lin_ChannelDetCheck(Channel, LIN_GOTOSLEEPINTERNAL_ID);

    if (E_OK == errorId)
    {
        locNodeCfg = &Lin_Handler[coreId]->config->channels[Channel];
        Lin_ChannelPtr = &Lin_Handler[coreId]->channelInfo[Channel];
        Lin_Handler[coreId]->channelStatus[Channel] = (uint8)LIN_CH_SLEEP;
        Lin_ChannelPtr->ChannelState = LIN_CH_SLEEP;
        Lin_ChannelPtr->nodeData.currentState = LIN_WAIT_FOR_WAKEUP;
        Lin_Handler[coreId]->wakeupFlag[Channel] = FALSE;
        if ((locNodeCfg->dataPtr.mode == LIN_UART_MASTER))
        {
            Lin_Handler[coreId]->sleepFlag[Channel] = TRUE;
        }
        retVal = E_OK;

    }
#if(STD_ON == LIN_DEV_ERROR_DETECT)
    else if (E_NOT_OK != errorId)
    {
        (void)Det_ReportError(LIN_MODULE_ID, 0, LIN_GOTOSLEEPINTERNAL_ID, errorId);

    }
#endif /** #if(STD_ON == LIN_DEV_ERROR_DETECT) */

    return retVal;
}

/******************************************************************************************************
 * Lin_WakeUp                 : LIN function generates a wakeup pulse to the LIN channel requested.
   Return type                : Std_ReturnType E_OK when wakeup command is accepted
                                               E_NOT_OK when wakeup command is not accepted or error
   Parameter                  : Channel which needs wakeup
******************************************************************************************************/
Std_ReturnType Lin_Wakeup(uint8 Channel)
{
    Lin_ChannelInfoType *Lin_ChannelPtr;
    Std_ReturnType retVal = E_NOT_OK;
    Std_ReturnType errorId;
    Lin_ChannelPtr = NULL_PTR;
    uint8 coreId = Lin_GetCoreId();

    /* Check Lin driver common parameter */
    errorId = Lin_ChannelDetCheck(Channel, LIN_WAKEUP_ID);

    if (E_OK == errorId)
    {
        Lin_ChannelPtr = &Lin_Handler[coreId]->channelInfo[Channel];

        if (Lin_ChannelPtr->ChannelState == LIN_CH_SLEEP)
        {
            Lin_Handler[coreId]->wakeupSelfFlag[Channel] = TRUE;
            Lin_ChannelPtr->ChannelState = LIN_OPERATIONAL;
            Lin_Handler[coreId]->channelStatus[Channel] = LIN_CH_OPERATIONAL;
            Lin_HwWakeup(Channel);
            retVal = E_OK;
        }
        else
        {
            errorId = LIN_E_STATE_TRANSITION;
        }
    }

#if(STD_ON == LIN_DEV_ERROR_DETECT)
    if ((E_OK != errorId) && (E_NOT_OK != errorId))
    {
        (void)Det_ReportError(LIN_MODULE_ID, 0, LIN_WAKEUP_ID, errorId);
    }
#endif /** #if(STD_ON == LIN_DEV_ERROR_DETECT) */

    return retVal;
}

/******************************************************************************************************
 * Lin_WakeUpInterval         : LIN function does not generate a wakeup pulse to the LIN channel requested.
   Return type                : Std_ReturnType E_OK when wakeup command is accepted
                                               E_NOT_OK when wakeup command is not accepted or error
   Parameter                  : Channel which needs wakeup
******************************************************************************************************/
Std_ReturnType Lin_WakeupInternal(uint8 Channel)
{
    Lin_ChannelInfoType *Lin_ChannelPtr = NULL_PTR;
    Std_ReturnType retVal = E_NOT_OK;
    Std_ReturnType errorId;
    uint8 coreId = Lin_GetCoreId();

    /* Check Lin driver common parameter */
    errorId = Lin_ChannelDetCheck(Channel, LIN_WAKEUPINTERNAL_ID);

    if (E_OK == errorId)
    {
        Lin_ChannelPtr = &Lin_Handler[coreId]->channelInfo[Channel];

        if (Lin_ChannelPtr->ChannelState == LIN_CH_SLEEP)
        {
            Lin_ChannelPtr->ChannelState = LIN_OPERATIONAL;
            Lin_Handler[coreId]->channelStatus[Channel] = LIN_CH_OPERATIONAL;
            Lin_ChannelPtr->nodeData.currentState = LIN_ACTIVE;
            retVal = E_OK;
        }
        else
        {
            errorId = LIN_E_STATE_TRANSITION;
        }
    }
#if(STD_ON == LIN_DEV_ERROR_DETECT)
    if ((E_OK != errorId) && (E_NOT_OK != errorId))
    {
        (void)Det_ReportError(LIN_MODULE_ID, 0, LIN_WAKEUPINTERNAL_ID, errorId);
    }
#endif /** #if(STD_ON == LIN_DEV_ERROR_DETECT) */

    return retVal;
}

/******************************************************************************************************
 * Lin_GetStatus               : LIN function indicates the current transmission, reception or operation
                                status of the LIN driver.
   Return type                 : Lin_StatusType
                                 LIN_NOT_OK            -- DET or DEM error occurred
                                 LIN_TX_OK             -- Transmission successful
                                 LIN_TX_BUSY           -- Transmission ongoing (Header or response)
                                 LIN_TX_HEADER_ERROR   -- Error in transmission of header
                                 LIN_RX_OK             -- Reception successful
                                 LIN_RX_BUSY           -- Reception ongoing
                                 LIN_RX_ERROR          -- Error in reponse. Frame error, Checksum error
                                 LIN_RX_NO_RESPONSE    -- No response byte has been received
                                 LIN_OPERATIONAL       -- Normal operation. Frames are being transmitted normally
                                 LIN_CH_SLEEP          -- Sleep mode operation

   Parameter1                  : Channel ID
   Parameter2                  : Pointer to pointer to shadow buffer or LIN Hardware receive buffer
******************************************************************************************************/
Lin_StatusType Lin_GetStatus(uint8 Channel, uint8 **Lin_SduPtr)
{
    const Lin_Uart *locNodeCfg;
    Lin_ChannelInfoType *Lin_ChannelPtr;
    Lin_StatusType retVal = LIN_NOT_OK;
    Std_ReturnType errorId;
    Lin_ChannelPtr = NULL_PTR;
    uint8 coreId = Lin_GetCoreId();

    /* Check Lin driver common parameter */
    errorId = Lin_ChannelDetCheck(Channel, LIN_GETSTATUS_ID);

    if (E_OK == errorId)
    {
        locNodeCfg = &Lin_Handler[coreId]->config->channels[Channel];
        /* this api support master mode only */
        if (locNodeCfg->dataPtr.mode == LIN_UART_MASTER)
        {
            Lin_ChannelPtr = &Lin_Handler[coreId]->channelInfo[Channel];
            if (Lin_SduPtr != NULL_PTR)
            {
                if (LIN_CH_OPERATIONAL == Lin_Handler[coreId]->channelStatus[Channel])
                {
                    retVal = Lin_ChannelPtr->ChannelState;
                    if ((uint8)LIN_SLAVE_RESPONSE == Lin_ChannelPtr->nodeData.drc)
                    {
                        *Lin_SduPtr = Lin_ChannelPtr->nodeData.rxframe;
                    }
                    else
                    {
                        *Lin_SduPtr = Lin_ChannelPtr->nodeData.txframe;
                    }
                }
                else if (LIN_CH_SLEEP_PENDING == Lin_Handler[coreId]->channelStatus[Channel])
                {
                    retVal = LIN_CH_SLEEP;
                    Lin_Handler[coreId]->channelStatus[Channel] = (uint8)LIN_CH_SLEEP;
                }
                else
                {
                    retVal = LIN_CH_SLEEP;
                }
            }
            else
            {
                errorId = LIN_E_PARAM_POINTER;
            }
        }
        else
        {
            errorId = LIN_E_INVALID_CHANNEL;
        }
    }

#if(STD_ON == LIN_DEV_ERROR_DETECT)
    if ((E_OK != errorId) && (E_NOT_OK != errorId))
    {
        (void)Det_ReportError(LIN_MODULE_ID, 0, LIN_GETSTATUS_ID, errorId);
    }
#endif /** #if(STD_ON == LIN_DEV_ERROR_DETECT) */

    return retVal;
}

/******************************************************************************************************
 * Lin_CheckWakeup           : LIN function to identify the corresponding LIN channel after Lin wakeup
                                caused by LIN transceiver
   Return type                : Std_ReturnType E_OK
                                               E_NOT_OK
   Parameter                  : ChannelId on which wakeup check should be performed
******************************************************************************************************/
Std_ReturnType Lin_CheckWakeup (uint8 Channel)
{
    Std_ReturnType retVal = E_NOT_OK;
    Std_ReturnType errorId;
    uint8 coreId = Lin_GetCoreId();

    /* Check Lin driver common parameter */
    errorId = Lin_ChannelDetCheck(Channel, LIN_CHECKWAKEUP_ID);

    if (E_OK == errorId)
    {
        if (Lin_Handler[coreId]->wakeupFlag[Channel] == TRUE)
        {
            Lin_Handler[coreId]->wakeupFlag[Channel] = FALSE;
            retVal = E_OK;
        }
    }
#if(STD_ON == LIN_DEV_ERROR_DETECT)
    else if (E_NOT_OK != errorId)
    {
        (void)Det_ReportError(LIN_MODULE_ID, 0, LIN_CHECKWAKEUP_ID, errorId);
    }
#endif /** #if(STD_ON == LIN_DEV_ERROR_DETECT) */

    return retVal;
}



#if ( LIN_VERSION_INFO_API == STD_ON )
/******************************************************************************************************
 * Lin_GetVersionInfo         : Get driver Version
   Return type                : void
   Parameter                  : Pointer to VersionInfo struct
******************************************************************************************************/
void Lin_GetVersionInfo (Std_VersionInfoType * VersionInfo)
{
    /* #10 Check validity of parameter versioninfo. Note: no uninit check is performed */
    if (VersionInfo == NULL_PTR)
    {
#if ((LIN_DEV_ERROR_REPORT == STD_ON) && (LIN_DEV_ERROR_DETECT == STD_ON))
        (void) Det_ReportError(LIN_MODULE_ID, LIN_DET_ERROR, LIN_GETVERSIONINFO_SERVICE_ID, LIN_E_PARAM_POINTER);
#endif /* LIN_DEV_ERROR_DETECT == STD_ON */
    }
    else
    {
        VersionInfo->vendorID = LIN_VENDOR_ID;
        VersionInfo->moduleID = LIN_MODULE_ID;
        VersionInfo->sw_major_version = LIN_SW_MAJOR_VERSION;
        VersionInfo->sw_minor_version = LIN_SW_MINOR_VERSION;
        VersionInfo->sw_patch_version = LIN_SW_PATCH_VERSION;
    }
}
#endif

#define LIN_STOP_SEC_CODE
#include "Lin_MemMap.h"

#define LIN_START_SEC_CODE_FAST
#include "Lin_MemMap.h"
/******************************************************************************************************
 * Lin_SendFrame               : LIN function to transmit header and response of the frame
                                 The function generates the header part (Break field, Sync byte and PID field)
                                 of the LIN frame. Functionality: Sends frame, Receives response, Calculates
                                 checksum and validates checksum of the receive frame
   Return type                 : Std_ReturnType
                                 E_OK                 -- Tranmission successful
                                 E_NOT_OK             -- Transmission not successful

   Parameter1                  : Channel ID
   Parameter2                  : Pointer to PDU containing PID, Checksum model and Response type, Data length
******************************************************************************************************/
Std_ReturnType Lin_SendFrame (uint8 Channel, const Lin_PduType *PduInfoPtr)
{
    const Lin_Uart *locNodeCfg;
    Lin_ChannelInfoType *Lin_ChannelPtr;
    Lin_NodeDataType *locNodeData;
    Std_ReturnType    retVal = E_NOT_OK;
    Std_ReturnType errorId;
    Lin_StatusType ChannelState = LIN_NOT_OK;
    uint8 coreId = Lin_GetCoreId();

    /* Check Lin driver common parameter */
    errorId = Lin_ChannelDetCheck(Channel, LIN_SENDFRAME_ID);

    if (E_OK == errorId)
    {
        locNodeCfg = &Lin_Handler[coreId]->config->channels[Channel];
        if (locNodeCfg->dataPtr.mode == LIN_UART_MASTER)
        {
            if (PduInfoPtr != NULL_PTR)
            {
                Lin_ChannelPtr = &Lin_Handler[coreId]->channelInfo[Channel];
                Lin_ChannelPtr->pduInfo = PduInfoPtr;

                if (Lin_ChannelPtr->pduInfo->Dl > 8U)
                {
                    return E_NOT_OK;
                }

                locNodeData = &(Lin_ChannelPtr->nodeData);

                ChannelState = Lin_ChannelPtr->ChannelState;
                /* rst module when last frame not recieve done */
                if ((ChannelState != LIN_NOT_OK) && (ChannelState != LIN_CH_SLEEP))
                {
                    if ((ChannelState == LIN_RX_BUSY) || (ChannelState == LIN_TX_BUSY) || (ChannelState == LIN_RX_NO_RESPONSE))
                    {
                        Lin_HwRstMod(Channel);
                    }

                    for (uint8 i = 0; i < Lin_ChannelPtr->pduInfo->Dl; i++)
                    {
                        locNodeData->txframe[i] = 0;
                    }

                    locNodeData->currentState = LIN_ACTIVE;
                    locNodeData->framestate = LIN_FRAMEIDLE;
                    locNodeData->error = LIN_OK;
                    Lin_ChannelPtr->ChannelState = LIN_OPERATIONAL;
                    Lin_HwSetNodePdu(locNodeData, PduInfoPtr);
                    retVal = Lin_HwSendFrame(Channel);
                }
                else
                {
                    errorId = LIN_E_STATE_TRANSITION;
                }
            }
            else
            {
                errorId = LIN_E_PARAM_POINTER;
            }
        }
        else
        {
            errorId = LIN_E_INVALID_CHANNEL;
        }
    }

#if(STD_ON == LIN_DEV_ERROR_DETECT)
    if ((E_OK != errorId) && (E_NOT_OK != errorId))
    {
        (void)Det_ReportError(LIN_MODULE_ID, 0, LIN_SENDFRAME_ID, errorId);
    }
#endif /** #if(STD_ON == LIN_DEV_ERROR_DETECT) */

    return retVal;
}

#define LIN_STOP_SEC_CODE_FAST
#include "Lin_MemMap.h"

#ifdef __cplusplus
}
#endif

/* End of file */
